
#include <event2/util.h>
#include <event2/event.h>
#include <stdlib.h>
#include <stdio.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include "socket5.h"

#ifdef WIN32
#include <WinSock2.h>
#else
#include <sys/socket.h>
#include <signal.h>
#endif // DEBUG

#define MAX_USERS 7777

#define BUFFER_SIZE 4096

extern event_base* g_base;


void if_socket_error_exit(int num)
{
	int errnum = EVUTIL_SOCKET_ERROR();
	char *errstr = evutil_socket_error_to_string(errnum);
	printf("%s", errstr);
	exit(num);
}

void client_socket_read_timeout(evutil_socket_t socket, short event, void* arg)
{
	//移除事件监听
	//如果关闭套接字后，事件循环中，该套接字所绑定的读事件是未决的 怎么搞
	//目前是单线程程序，如果以后是多线程怎么办
	client* user = (client*)user;
    client_release(user);
}

void listen_read_call_back(evutil_socket_t socket, short what, void* arg)
{
	struct sockaddr_in client_addr;
	socklen_t client_addr_len = 0;
	evutil_socket_t client_sock = accept(socket, (struct sockaddr*)&client_addr, &client_addr_len);
	if (client_sock <= 0)
	{
		return;
	}
	evutil_make_socket_nonblocking(socket);
	printf("connected form %s,...\n", inet_ntoa(client_addr.sin_addr));
	struct client* user = client_new();
	//add event
	//设置超时事件，300秒没有收到消息，踢掉链接
	event* client_timeout_event = event_new(g_base, client_sock, EV_TIMEOUT, client_socket_read_timeout, (void*)user);
	event* client_socket_read_event = event_new(g_base, client_sock, EV_READ,
		client_select_method, (void*)user);
	event_add(client_socket_read_event, NULL);
	timeval time;
	time.tv_sec = 60;
	time.tv_usec = 0;
	event_add(client_timeout_event, &time);
	user->read_event = client_socket_read_event;
	user->timeout_event = client_timeout_event;
}

int main(int argc, char** argv)
{
#ifndef WIN32
	signal(SIGPIPE, SIG_IGN);
#endif // !WIN32

	int errnum;
	char* errstr;
	evutil_socket_t listenser = socket(AF_INET, SOCK_STREAM, 0);
	if (!listenser) {
		if_socket_error_exit(1);
	}
	evutil_make_socket_nonblocking(listenser);
	evutil_make_listen_socket_reuseable(listenser);
	evutil_make_socket_closeonexec(listenser);
	struct sockaddr_in sin;
	sin.sin_family = AF_INET;
	sin.sin_port = 1020;
	sin.sin_addr.s_addr = htonl(INADDR_ANY);
	ssize_t server_addr_len = sizeof(sin);
	if (bind(listenser, (struct sockaddr*)&sin, server_addr_len) < 0)
	{
		if_socket_error_exit(2);
	}
	if (listen(listenser, 7) < 0)
	{
		if_socket_error_exit(3);
	}
	event_config * config = event_config_new();
#ifdef WIN32
	errnum = event_config_set_flag(config, EVENT_BASE_FLAG_START_IOCP);
	if (errnum == -1)
	{
		printf("strat iocp error\n");
		if_socket_error_exit(3);
		return 2;
	}
#else
	errnum = event_config_require_features(config, EV_FEATURE_ET);
	if (errnum == -1)
	{
		printf("support et error\n");
		if_socket_error_exit(4);
		return 5;
	}
	errnum = event_config_set_flag(config, EVENT_BASE_FLAG_EPOLL_USE_CHANGELIST);
	if (errnum == -1)
	{
		printf("use changelist error\n");
		if_socket_error_exit(5);
		return 6;
	}
#endif // WIN32
	g_base = event_base_new();
	event *listenEvent = event_new(g_base, listenser, EV_READ | EV_PERSIST, listen_read_call_back, (void*)listenser);
	event_base_loop(g_base, EVLOOP_NONBLOCK);
	evutil_closesocket(listenser);
	event_free(listenEvent);
	event_base_free(g_base);
	evutil_closesocket(listenser);
	return 0;
}
